package mipo.top.base.service.impl;

import com.alibaba.fastjson.JSONObject;
import mipo.top.base.Dto.UserInfo;
import mipo.top.base.Dto.WechatDto;
import mipo.top.base.Vo.LoginphoneVo;
import mipo.top.base.constant.LoginConstant;
import mipo.top.base.constant.wechatRegisterConstant;
import mipo.top.base.exception.BusinessException;
import mipo.top.base.jwt.JwtUtils;
import mipo.top.base.jwt.RsaUtils;
import mipo.top.base.service.ILoginService;
import mipo.top.base.util.*;
import mipo.top.system.domain.Menu;
import mipo.top.system.mapper.MenuMapper;
import mipo.top.system.mapper.PermissionMapper;
import mipo.top.users.Vo.LogininfoVo;
import mipo.top.users.domain.Logininfo;
import mipo.top.users.domain.Wxuser;
import mipo.top.users.mapper.LogininfoMapper;
import mipo.top.users.mapper.WxuserMapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.security.PrivateKey;
import java.util.HashMap;
import java.util.List;

@Service
public class LoginServiceimpl implements ILoginService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private MenuMapper menuMapper;
    @Autowired
    private WxuserMapper wxuserMapper;
    @Value("${jwt.rsa.pri}")
    private String jwtprivateKey;


    @Override
    public HashMap<String, Object> account(LogininfoVo logininfoVo) {
        Logininfo logininfo = logininfoMapper.findByUsernameAndType(logininfoVo);
        if(logininfo==null){
            throw new BusinessException("请输入正确的账号或密码");
        }
        String s = logininfo.getSalt() + logininfoVo.getPassword();
        String password = MD5Utils.encrypByMd5(s);
        if (!password.equals(logininfo.getPassword())){
            throw new BusinessException("请输入正确的账号或密码");
        }
        HashMap<String, Object> map = loginSuccessJwtHandler(logininfo);
        return map;
    }

    @Override
    public HashMap<String, Object> phoneAccount(LoginphoneVo loginphoneVo) {
        String phone = loginphoneVo.getPhone();
        Logininfo logininfo = logininfoMapper.findphone(phone);
        if (logininfo==null){
            throw new BusinessException("手机号码错误，或用户不存在");
        }
        String phoneCode = (String) redisTemplate.opsForValue().get(LoginConstant.PHONELOGINKEY+phone);
        String smsCode = loginphoneVo.getSmsCode();
        if (!phoneCode.equals(smsCode)){
            throw new BusinessException("手机验证码错误");
        }
        HashMap<String, Object> map = loginSuccessJwtHandler(logininfo);
        return map;
    }

    @Override
    public JsonResult wechat(WechatDto wechatDto) {
        if (StringUtils.isBlank(wechatDto.getCode())){
            throw new BusinessException("参数不能为空");
        }
        Pair<String, String> pair = getOpenidandToken(wechatDto.getCode());
        Wxuser wxuser = wxuserMapper.findByopenid(pair.getRight());
        if(wxuser!=null&&wxuser.getUserId()!=null){
            Logininfo logininfo = logininfoMapper.findByUserId(wxuser.getUserId());
            HashMap<String, Object> map = loginSuccessJwtHandler(logininfo);
            return JsonResult.me().setResultData(map);
        }
        StringBuffer sb = new StringBuffer()
                .append("?access_token=")
                .append(pair.getLeft())
                .append("&openId=")
                .append(pair.getRight());
        return JsonResult.me().setMsg("未绑定微信").setResultData(sb);
    }

    @NotNull
    public HashMap<String, Object> loginSuccessJwtHandler(Logininfo logininfo){
        // 1.创建UserInfo对象，存储logininfo对象，并用于后续赋值
        UserInfo userInfo = new UserInfo();
        userInfo.setLogininfo(logininfo);
        // 2.判断是后台用户登录才需要设置菜单信息、权限信息，类型为0那么就是后台用户登录
        if(logininfo.getType() == 0){
            // 2.1.获取用户权限信息，我们只需要sn权限编码即可
            List<String> permissions = permissionMapper.loadOwnPermissionByLogininId(logininfo.getId());
            // 2.2.获取用户菜单信息
            List<Menu> menus = menuMapper.loadOwnMenuByLogininId(logininfo.getId());
            // 2.3.将菜单信息，权限信息放入到userinfo对象中
            userInfo.setPermissions(permissions);
            userInfo.setMenus(menus);
        }
        // 3.根据密钥文件名称获取到密钥
        PrivateKey privateKey = RsaUtils.getPrivateKey(this.getClass().getClassLoader().getResource(jwtprivateKey).getFile());
        // 4.根据密钥、用户信息、获取JWT加密串
        String token = JwtUtils.generateTokenExpireInMinutes(userInfo, privateKey, 3000);
        // 5.按照正常逻辑我们直接返回token给前端即可，但是那样前端需要解密，我们使用简化版本JWT，还是返回用户信息
        // 封装token、用户信息、权限信息、菜单信息给前端
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("logininfo", logininfo);
        map.put("permissions", userInfo.getPermissions());
        map.put("menus", userInfo.getMenus());
        return map;
    }

    private Pair<String,String> getOpenidandToken(String code){
        String tokenUrl = wechatRegisterConstant.TOKEN_URL
                .replace("APPID", wechatRegisterConstant.APPID)
                .replace("SECRET", wechatRegisterConstant.SECRET)
                .replace("CODE", code);
        String httpGet = HttpUtil.httpGet(tokenUrl);
        JSONObject jsonObject = JSONObject.parseObject(httpGet);
        String access_token = jsonObject.getString("access_token");
        String openId = jsonObject.getString("openid");
        return Pair.of(access_token,openId);
    }
}
